package com.pmdb.core.data;

import java.util.Collections;
import java.util.SortedSet;
import java.util.TreeSet;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

import org.apache.log4j.Logger;
import org.hibernate.annotations.Sort;
import org.hibernate.annotations.SortType;

@Entity
@Table(name = "T_PERSON")
public class Person {

   private static final Logger LOG = Logger.getLogger(Person.class);
   
   @Id @GeneratedValue
   @Column(name = "ID")
   private Long id;
   
   @Column(name = "FULL_NAME")
   private String fullName;
   
   @ManyToMany(
         mappedBy = "producers"
   )
   @Sort(type = SortType.NATURAL)
   private SortedSet<Movie> moviesAsProducer;
   
   @ManyToMany(
         mappedBy = "directors"
   )
   @Sort(type = SortType.NATURAL)
   private SortedSet<Movie> moviesAsDirector;
   
   @ManyToMany(
         mappedBy = "writers"
   )
   @Sort(type = SortType.NATURAL)
   private SortedSet<Movie> moviesAsWriter;
   
   @ManyToMany(
         mappedBy = "actors"
   )
   @Sort(type = SortType.NATURAL)
   private SortedSet<Movie> moviesAsActor;
   
   public Person() {
      this.moviesAsProducer = new TreeSet<Movie>();
      this.moviesAsDirector = new TreeSet<Movie>();
      this.moviesAsWriter = new TreeSet<Movie>();
      this.moviesAsActor = new TreeSet<Movie>();
   }

   public Person(String fullName) {
      this();
      this.fullName = fullName;
   }

   public Long getId() {
      return id;
   }

   public void setId(Long id) {
      this.id = id;
   }

   public String getFullName() {
      return fullName;
   }

   public void setFullName(String fullName) {
      this.fullName = fullName;
   }

   public SortedSet<Movie> getMoviesAsProducer() {
      return Collections.unmodifiableSortedSet(this.moviesAsProducer);
   }

   public void addMovieAsProducer(Movie movie) {
      this.addMovieAsProducer(movie, true);
   }

   public void addMovieAsProducer(Movie movie, boolean linkBack) {
      if(movie == null) {
         throw new IllegalArgumentException("Null movie!");
      }
      this.moviesAsProducer.add(movie);
      LOG.debug("New movie for this producer: " + fullName);
      if(linkBack) {
         movie.addProducer(this, false);
      }
   }
   
   public void removeMovieAsProducer(Movie movie) {
      this.removeMovieAsProducer(movie, true);
   }
   
   public void removeMovieAsProducer(Movie movie, boolean removeLinkBack) {
      if(movie == null) {
         throw new IllegalArgumentException("Null movie!");
      }
      this.moviesAsProducer.remove(movie);
      if(removeLinkBack) {
         movie.removeProducer(this, false);
      }
   }

   public SortedSet<Movie> getMoviesAsDirector() {
      return Collections.unmodifiableSortedSet(this.moviesAsDirector);
   }

   public void addMovieAsDirector(Movie movie) {
      this.addMovieAsDirector(movie, true);
   }

   public void addMovieAsDirector(Movie movie, boolean linkBack) {
      if(movie == null) {
         throw new IllegalArgumentException("Null movie!");
      }
      this.moviesAsDirector.add(movie);
      LOG.debug("New movie for this director: " + fullName);
      if(linkBack) {
         movie.addDirector(this, false);
      }
   }
   
   public void removeMovieAsDirector(Movie movie) {
      this.removeMovieAsDirector(movie, true);
   }
   
   public void removeMovieAsDirector(Movie movie, boolean removeLinkBack) {
      if(movie == null) {
         throw new IllegalArgumentException("Null movie!");
      }
      this.moviesAsDirector.remove(movie);
      if(removeLinkBack) {
         movie.removeDirector(this, false);
      }
   }

   public SortedSet<Movie> getMoviesAsWriter() {
      return Collections.unmodifiableSortedSet(this.moviesAsWriter);
   }

   public void addMovieAsWriter(Movie movie) {
      this.addMovieAsWriter(movie, true);
   }

   public void addMovieAsWriter(Movie movie, boolean linkBack) {
      if(movie == null) {
         throw new IllegalArgumentException("Null movie!");
      }
      this.moviesAsWriter.add(movie);
      LOG.debug("New movie for this writer: " + fullName);
      if(linkBack) {
         movie.addWriter(this, false);
      }
   }
   
   public void removeMovieAsWriter(Movie movie) {
      this.removeMovieAsWriter(movie, true);
   }
   
   public void removeMovieAsWriter(Movie movie, boolean removeLinkBack) {
      if(movie == null) {
         throw new IllegalArgumentException("Null movie!");
      }
      this.moviesAsWriter.remove(movie);
      if(removeLinkBack) {
         movie.removeWriter(this, false);
      }
   }

   public SortedSet<Movie> getMoviesAsActor() {
      return Collections.unmodifiableSortedSet(moviesAsActor);
   }

   public void addMovieAsActor(Movie movie) {
      this.addMovieAsActor(movie, true);
   }

   public void addMovieAsActor(Movie movie, boolean linkBack) {
      if(movie == null) {
         throw new IllegalArgumentException("Null movie!");
      }
      this.moviesAsActor.add(movie);
      LOG.debug("New movie for this actor: " + fullName);
      if(linkBack) {
         movie.addActor(this, false);
      }
   }
   
   public void removeMovieAsActor(Movie movie) {
      this.removeMovieAsActor(movie, true);
   }
   
   public void removeMovieAsActor(Movie movie, boolean removeLinkBack) {
      if(movie == null) {
         throw new IllegalArgumentException("Null movie!");
      }
      this.moviesAsActor.remove(movie);
      if(removeLinkBack) {
         movie.removeActor(this, false);
      }
   }
   
   @Override
   public String toString() {
      StringBuilder strBld = new StringBuilder();
      strBld.append("Person={[");
      strBld.append(id);
      strBld.append("] ");
      strBld.append(fullName);
      strBld.append("}");
      
      return strBld.toString();
   }
}
